package org.jetlinks.demo.protocol.siterwell.tcp;

import lombok.AllArgsConstructor;
import lombok.Getter;
import org.jetlinks.demo.protocol.siterwell.tcp.constant.DirectiveType;
import org.jetlinks.demo.protocol.siterwell.tcp.constant.MessageFixedHeader;
import org.jetlinks.demo.protocol.siterwell.tcp.message.*;
import org.jetlinks.demo.protocol.siterwell.tcp.util.ByteUtils;

import java.util.Optional;
import java.util.function.Supplier;

@AllArgsConstructor
@Getter
public enum MessageType {
    // 心跳数据
    PING(MessageFixedHeader.HEART, DirectiveType.EMPTY, "心跳数据", D2SPing::new),
    PING1(MessageFixedHeader.DAMAGE, DirectiveType.EMPTY, "心跳数据", D2SPing::new),
    // 指令消息
    AUTH_REQ(MessageFixedHeader.COMMAND, DirectiveType.LOGIN, "登录请求", D2SAuthRequest::new),
    ADD_DEVICE(MessageFixedHeader.COMMAND, DirectiveType.ADD_DEVICE, "添加设备", D2SAddDevice::new),
    REMOVE_DEVICE(MessageFixedHeader.COMMAND, DirectiveType.REMOVE_DEVICE, "删除设备", D2SRemoveDevice::new),
    DEVICE_ALARM(MessageFixedHeader.COMMAND, DirectiveType.ALARM, "设备报警", D2SDeviceAlarm::new),
    RESTORE_LINK(MessageFixedHeader.COMMAND, DirectiveType.RESTORE_LINK, "恢复连接", D2SRestoreLink::new),
    DEPLOY_FOR_DEFENCE(MessageFixedHeader.COMMAND, DirectiveType.DEPLOY_FOR_DEFENCE, "布防", D2SDeployForDefence::new),
    DEPLOY_REMOVE(MessageFixedHeader.COMMAND, DirectiveType.DEPLOY_REMOVE, "撤防", D2SDeployRemove::new),
    NORMAL(MessageFixedHeader.COMMAND, DirectiveType.NORMAL, "正常", D2SDeviceNormalStatus::new),
    MUTE(MessageFixedHeader.COMMAND, DirectiveType.MUTE, "静音", D2SDeviceMuteStatus::new),
    FAULT(MessageFixedHeader.COMMAND, DirectiveType.FAULT, "故障", D2SDeviceFaultStatus::new),
    VOLTAGE_NORMAL(MessageFixedHeader.COMMAND, DirectiveType.VOLTAGE_NORMAL, "电压正常", D2SVoltageNormal::new),
    READ_SENSOR(MessageFixedHeader.COMMAND, DirectiveType.READ_SENSOR, "读取传感器数据响应", D2SReadSensorReply::new),
    POWER_ON(MessageFixedHeader.COMMAND, DirectiveType.POWER_ON, "上电", D2SPowerOn::new),
    POWER_FAILURE(MessageFixedHeader.COMMAND, DirectiveType.POWER_FAILURE, "断电", D2SPowerFailure::new);

    private MessageFixedHeader fixedHeader;
    private DirectiveType directive;
    private String text;
    private Supplier<TcpPayload> payloadSupplier;

    public TcpPayload read(byte[] payload, int offset) {
        TcpPayload tcpPayload = payloadSupplier.get();
        tcpPayload.fromBytes(payload, offset);
        return tcpPayload;
    }

    public byte[] toBytes(TcpPayload data) {
        if (data == null) {
            return new byte[0];
        }
        return data.toBytes();
    }

    public static Optional<MessageType> of(byte[] payload) {
        String hexPayload = ByteUtils.byte2HexStr(payload);
        String fixedHeader = ByteUtils.subHexStrByByte(hexPayload, 0, 1);
        Optional<MessageFixedHeader> header = MessageFixedHeader.of(fixedHeader);
        if (!header.isPresent()) {
            return Optional.empty();
        }
        MessageFixedHeader actualHeader = header.get();

        if (MessageFixedHeader.HEART.equals(actualHeader) ||
                MessageFixedHeader.DAMAGE.equals(actualHeader)) {
            return Optional.of(PING);
        }
        if (!MessageFixedHeader.COMMAND.equals(actualHeader)) {
            return Optional.empty();
        }

        // 遍历处理命令请求
        String directiveCode = ByteUtils.subHexStrByByte(hexPayload, 11, 12);
        Optional<DirectiveType> directiveType = DirectiveType.of(directiveCode);
        if (!directiveType.isPresent()) {
            return Optional.empty();
        }
        DirectiveType actualDirective = directiveType.get();

        MessageType[] messageTypes = values();
        int len = messageTypes.length;
        for (int i = 0; i < len; i++) {
            MessageType curMessageType = messageTypes[i];
            MessageFixedHeader curFixedHeader = curMessageType.getFixedHeader();
            if (!MessageFixedHeader.COMMAND.equals(curFixedHeader)) {
                continue;
            }
            DirectiveType curDirectiveType = curMessageType.getDirective();
            if (curDirectiveType.equals(actualDirective)) {
                return Optional.of(curMessageType);
            }
        }

        return Optional.empty();

    }
}
